package gpi.object;

import gpi.algo.Algorithm;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Task {
	private String name;
	private int duration;
	private int minTime;
	private int maxTime;
	private int margin;
	private int freeMargin;
	private int seqTime;

	private List<Task> listPredecessors = new ArrayList<Task>();
	private Map<Resource,Integer> mapResources = new HashMap<Resource,Integer>();
	
	/**
	 * Most used constructor
	 * 
	 * @param duration
	 * @param listPredecessors
	 */
	public Task(String name, int duration, List<Task> listPredecessors) {
		this.name = name;
		this.duration = duration;
		for (Task task : listPredecessors) {
			if (this.listPredecessors != null
					&& !this.listPredecessors.contains(task)) {
				this.listPredecessors.add(task);
			}
		}
		if (name != "FIN") {
			Algorithm.getInstance().addTask(this);
		}
	}

	/**
	 * Constructor used when minTime and maxTime are also known (mostly used for
	 * testing)
	 * 
	 * @param duration
	 * @param minTime
	 * @param maxTime
	 * @param listPredecessors
	 */
	public Task(String name, int duration, int minTime, int maxTime,
			List<Task> listPredecessors) {
		this(name, duration, listPredecessors);
		this.minTime = minTime;
		this.maxTime = maxTime;
	}

	public List<Task> getSuccessors() {
		Map<String, Task> allTasks = Algorithm.getInstance().getAllTasks();
		List<Task> listSuccessors = new ArrayList<Task>();
		for (String taskName : allTasks.keySet()) {
			Task successor = allTasks.get(taskName);
			if (successor.getListPredecessors().contains(this)) {
				listSuccessors.add(successor); // the value corresponds to the duration
										// between the task and her successor
			}
		}
		return listSuccessors;
	}
	
	public int lft() {
		int lft = this.maxTime + this.duration;
		return lft;
	}
	
	public int hla() {
		int predecessorsEnd = 0;
		int hla;

		if (this.getListPredecessors().size() > 0) {
			for (Task task : this.getListPredecessors()) {
				predecessorsEnd = Math.max(predecessorsEnd, task.getSeqTime()
						+ task.getDuration());
			}
			hla = this.getSeqTime() - predecessorsEnd;
		} else {
			hla = 0;
		}

		return hla;
	}

	public int hlr() {
		int successorsBegin = 0;
		int hlr;
		boolean firstElement = true;

		if (this.getSuccessors().size() > 0) {
			for (Task task : this.getSuccessors()) {
				if (firstElement) {
					successorsBegin = task.getSeqTime();
					firstElement = false;
				}
				successorsBegin = Math.min(successorsBegin, task.getSeqTime());
			}
			int taskEnd = this.getSeqTime() + this.getDuration();
			hlr = successorsBegin - taskEnd;
		} else {
			hlr = 0;
		}

		return hlr;
	}

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name
	 *            the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * @return the duration
	 */
	public int getDuration() {
		return duration;
	}

	/**
	 * @param duration
	 *            the duration to set
	 */
	public void setDuration(int duration) {
		this.duration = duration;
	}

	/**
	 * @return the minTime
	 */
	public int getMinTime() {
		return minTime;
	}

	/**
	 * @param minTime
	 *            the minTime to set
	 */
	public void setMinTime(int minTime) {
		this.minTime = minTime;
	}

	/**
	 * @return the maxTime
	 */
	public int getMaxTime() {
		return maxTime;
	}

	/**
	 * @param maxTime
	 *            the maxTime to set
	 */
	public void setMaxTime(int maxTime) {
		this.maxTime = maxTime;
	}

	/**
	 * @return the listPredecessors
	 */
	public List<Task> getListPredecessors() {
		return listPredecessors;
	}

	/**
	 * @param listPredecessors
	 *            the listPredecessors to set
	 */
	public void setListPredecessors(List<Task> listPredecessors) {
		this.listPredecessors = listPredecessors;
	}
	
	/**
	 * @return the margin
	 */
	public int getMargin() {
		return margin;
	}

	/**
	 * @param margin the margin to set
	 */
	public void setMargin(int margin) {
		this.margin = margin;
	}

	/**
	 * @return the freeMargin
	 */
	public int getFreeMargin() {
		return freeMargin;
	}

	/**
	 * @param freeMargin the freeMargin to set
	 */
	public void setFreeMargin(int freeMargin) {
		this.freeMargin = freeMargin;
	}

	/**
	 * @return the mapResources
	 */
	public Map<Resource, Integer> getMapResources() {
		return mapResources;
	}
	
	/**
	 * @param name the resource's name
	 * @param requirement the requirement of this task for this resource
	 */
	public void addResource(String name, int requirement) {
		this.mapResources.put(Algorithm.getInstance().getResource(name), requirement);
	}

	/**
	 * @return the seqTime
	 */
	public int getSeqTime() {
		return seqTime;
	}

	/**
	 * @param seqTime the seqTime to set
	 */
	public void setSeqTime(int seqTime) {
		this.seqTime = seqTime;
	}

}
